﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Ionic.Zip;

namespace LAMSDK.IO
{
    public static class Zip
    {
        #region 属性
        /// <summary>
        /// 系统根目录
        /// </summary>
        private static readonly string RootPath;

        /// <summary>
        /// 默认编码
        /// </summary>
        private static readonly Encoding DefaultEncoding;

        /// <summary>
        /// 读取压缩文件时的默认参数
        /// </summary>
        private static readonly ReadOptions DefaultReadOptions;
        #endregion

        #region 构造函数
        /// <summary>
        /// 初始化
        /// </summary>
        static Zip()
        {
            RootPath = System.Web.HttpContext.Current.Server.MapPath("~/");
            DefaultEncoding = System.Text.Encoding.Default;
            DefaultReadOptions = new ReadOptions() { Encoding = DefaultEncoding };
        }
        #endregion

        #region 方法
        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="zipFilePath">压缩文件相对路径，空则为当前被压缩文件夹路径</param>
        /// <param name="dirPath">被压缩文件夹相对路径</param>
        /// <example>
        ///     <code>
        ///         LAMSDK.IO.ZipDirectory("App_Data/Log.zip","App_Data/Log");
        ///     </code>
        /// </example>
        /// <remarks>
        ///     被压缩文件夹不存在则抛出参数异常
        /// </remarks>
        public static void CompressDirectory(string zipFilePath, string dirPath) 
        {
            CompressDirectory(zipFilePath, dirPath, null);
        }

        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="zipFilePath"></param>
        /// <param name="dirPath"></param>
        /// <param name="password"></param>
        public static void CompressDirectory(string zipFilePath, string dirPath, string password)
        {
            CompressDirectory(zipFilePath, dirPath, password, null);
        }

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="zipFilePath"></param>
        /// <param name="dirPath"></param>
        /// <param name="password"></param>
        /// <param name="comment"></param>
        public static void CompressDirectory(string zipFilePath, string dirPath, string password, string comment)
        {
            //转换斜杠为反斜杠,转化为绝对路径
            dirPath = RootPath + dirPath.Replace(@"/", @"\");
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");

            //判断被压缩目录是否为空，空则抛出异常
            if (string.IsNullOrEmpty(dirPath) || !System.IO.Directory.Exists(dirPath))
            {
                throw new ArgumentNullException("被压缩文件夹不存在。");
            }

            //压缩文件名为空时使用文件夹名＋.zip  
            if (string.IsNullOrEmpty(zipFilePath))
            {
                if (dirPath.EndsWith(@"\"))
                {
                    dirPath = dirPath.Substring(0, dirPath.Length - 1);
                }
                zipFilePath = dirPath + ".zip";
            }

            //创建压缩文件
            using (ZipFile zip = new ZipFile(zipFilePath, DefaultEncoding))
            {
                if (!string.IsNullOrEmpty(password))
                {
                    zip.Password = password;
                }
                if(!string.IsNullOrEmpty(comment))
                {
                    zip.Comment = comment;
                }
                zip.AddDirectory(dirPath);
                zip.Save();
            }
        }

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="zipFilePath">压缩文件相对路径</param>
        /// <param name="filePath">被压缩文件相对路径</param>
        public static void CompressFile(string zipFilePath, string filePath)
        {
            CompressFiles(zipFilePath, new List<string> { filePath });
        }

        /// <summary>
        /// 压缩文件组
        /// </summary>
        /// <param name="zipFilePath">压缩文件相对路径</param>
        /// <param name="filesPath">压缩文件组</param>
        /// <example>
        ///     <code>
        ///         IEnumerable<string> filesPath=new List<string>();
        ///         filesPath.Add("App_Data/2010.txt");
        ///         filesPath.Add("App_Data/tst.log");
        ///         LAMSDK.IO.ZipFiles("App_Data/file.zip",filesPath)
        ///     </code>
        /// </example>
        /// <remarks>
        ///     自动排除不存在的文件
        /// </remarks>
        public static void CompressFiles(string zipFilePath, IEnumerable<string> filesPath)
        {
            //转换斜杠为反斜杠,转化为绝对路径
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");
            using (ZipFile zip = new ZipFile(RootPath + zipFilePath, DefaultEncoding))
            {
                foreach (string file in filesPath)
                {
                    string filePath=RootPath+file.Replace(@"/", @"\");
                    if (File.Exists(filePath))
                    {
                        zip.AddFile(filePath);
                    }
                }
                zip.Save();
            }
        }

        public static void ExtractFile(string zipFilePath, string dirPath,string fileName) 
        {
            //转换斜杠为反斜杠,转化为绝对路径
            dirPath = RootPath + dirPath.Replace(@"/", @"\");
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");
            using (ZipFile zip = ZipFile.Read(zipFilePath, DefaultReadOptions))
            {
                zip[fileName].Extract(dirPath);
            }
        }

        public static void ExtractFiles(string zipFilePath, string dirPath,IEnumerable<string> fileNames)
        {
            //转换斜杠为反斜杠,转化为绝对路径
            dirPath = RootPath + dirPath.Replace(@"/", @"\");
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");
            using (ZipFile zip = ZipFile.Read(zipFilePath, DefaultReadOptions))
            {
                foreach (string FileName in fileNames)
                {
                    zip[FileName].Extract(dirPath);
                }
            }
        }

        /// <summary>
        /// 解压所有文件
        /// </summary>
        /// <param name="zipFilePath"></param>
        /// <param name="dirPath"></param>
        /// <returns></returns>
        public static void ExtractAll(string zipFilePath, string dirPath)
        {
            //转换斜杠为反斜杠,转化为绝对路径
            dirPath = RootPath + dirPath.Replace(@"/", @"\");
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");
            
            if (string.IsNullOrEmpty(zipFilePath) || !File.Exists(zipFilePath))
            {
                throw new FileNotFoundException("压缩文件不存在");
            }
            //解压目录为空时使用压缩文件父目录
            if (dirPath == string.Empty)
            {
                dirPath = zipFilePath.Substring(0, dirPath.Length - 4)+@"\";
            }

            using (ZipFile zip = ZipFile.Read(zipFilePath, DefaultReadOptions))
            {
                zip.ExtractAll(dirPath);
            }
        }

        /// <summary>
        /// 在指定压缩文件删除单个文件
        /// </summary>
        /// <param name="zipFilePath"></param>
        /// <param name="fileName"></param>
        /// <remarks>
        ///     注意无法直接删除一个文件夹
        /// </remarks>
        public static void DeleteFile(string zipFilePath, string fileName)
        {
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");
            using (ZipFile zip = ZipFile.Read(@"E:\test.zip", DefaultReadOptions))
            {
                zip.RemoveEntry(fileName);
                zip.Save();
            }
        }

        /// <summary>
        /// 在指定压缩文件中删除多个文件
        /// </summary>
        /// <param name="zipFilePath"></param>
        /// <param name="fileName"></param>
        public static void DeleteFiles(string zipFilePath, IList<string> fileName) {
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");
            using (ZipFile zip = ZipFile.Read(zipFilePath, DefaultReadOptions))
            {
                zip.RemoveEntries(fileName);
                zip.Save();
            }
        }

        /// <summary>
        /// 返回压缩文件内文件列表
        /// </summary>
        /// <param name="zipFilePath">压缩文件相对路径</param>
        /// <returns>返回文件绝对路径</returns>
        public static IEnumerable<string> GetFileList(string zipFilePath) 
        {
            zipFilePath = RootPath + zipFilePath.Replace(@"/", @"\");
            IList<string> FileList = new List<string>();
            using (ZipFile zip = ZipFile.Read(zipFilePath, DefaultReadOptions))
            {
                foreach (ZipEntry entry in zip)
                {
                    FileList.Add(entry.FileName);
                }
            }
            return FileList;
        }
        #endregion

        #region 私有方法
        private static string ConvertToAbsolutePath(string path) {
            path = path.Replace(@"/",@"\");
            if (path.StartsWith(@"\")) {
                path = path.Remove(0,1);
            }
            path = RootPath + path;
            return path;
        }

        private static string GetDefaultDir(string path)
        {
            if (path.EndsWith(@"\"))
            {
                path = path.Remove(path.Length - 1, 1);
            }
            path = path + ".zip";
            return path;
        }

        private static string GetDefualtZipName(string path) 
        {
            if (path.EndsWith(@"\"))
            {
                path = path.Remove(path.Length - 1,1);
            }
            path = path + ".zip";
            return path;
        }

        #endregion
    }
}
